package com.ftg.learn.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ftg.learn.mapper.SysUserMapper;
import com.ftg.learn.service.SysUserService;
import com.ftg.learn.util.JwtUtil;
import com.ftg.learn.util.MD5Utils;
import com.ftg.learn.util.R;
import com.ftg.learn.util.TipUtil;
import com.ftg.learn.vo.SysUserListVo;
import com.ftg.learn.vo.SysUserLoginVo;
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 实现类
 *
 * @author 布衣
 */
@Service
public class SysUserServiceImpl implements SysUserService {

    //密盐不能外泄
    private final String secretKey = "secretKey";

    //按类型
    //按名称装配
    @Resource
    SysUserMapper sysUserMapper;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    ObjectMapper objectMapper;

    private Lock lock = new ReentrantLock();

//    @Autowired
//    public void setSysUserMapper(SysUserMapper sysUserMapper) {
//        this.sysUserMapper = sysUserMapper;
//    }

//    Restful Api  Rest : 表述性状态传递 [数据与展示要分离]

//     状态 : 码 200
//     返回信息: msg
//     内容 ：实现内容   List<SysUserListVo> 大     String 轻量级传输协议 JSON

    /**
     * 带缓存处理的查询 方法
     *
     * @return R<String>
     */
    @Override
    public R<String> all() {
        String obj = null;
        try {
            lock.lock();
            //先要从redis里面找
            obj = stringRedisTemplate.opsForValue().get("all");
            //命中返回
            if (obj == null || obj.isEmpty()) {
                //直接操作mysql
                List<SysUserListVo> all = sysUserMapper.all();

                String json = objectMapper.writeValueAsString(all);

                //all 转换成json结构字符串的方法
                stringRedisTemplate.opsForValue().set("all", json);
                return R.ok(json);
            }

        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        return R.ok(obj);
    }

    @Override
    public R<String> login(String username, String password) {
        if (StringUtils.isEmpty(username)) {
            return R.build(TipUtil.LOGIN_USERNAME_IS_EMPTY);
        }

        if (StringUtils.isEmpty(password)) {
            return R.build(TipUtil.LOGIN_PASSWORD_IS_EMPTY);
        }
        //先对password进行特定加密，以后再去查询用户表
        String encodePassword = MD5Utils.encodePassword(password);

        // 命中以后，还要返回用户信息
        SysUserLoginVo user = sysUserMapper.login(username);
        if (Objects.isNull(user)) {
            return R.build(TipUtil.LOGIN_USERNAME_ERROR);
        }

        if (!user.getPassword().equals(encodePassword)) {
            return R.build(TipUtil.LOGIN_PASSWORD_ERROR);
        }
        //信息进行加密操作
        Map<String, Object> map = new HashMap<>(4);
        map.put("username", user.getUsername());
        map.put("email", user.getEmail());
        map.put("mobile", user.getMobile());
        map.put("userId", user.getUserId());

        long times = 1000 * 60 * 60 * 24 * 7;

        String jsonToken = JwtUtil.createJWT(times, map);
        // 指定签名的时候使用的签名算法，也就是header那部分
        String prefix = "token-" + user.getUsername() + "_" + user.getUsername();
        stringRedisTemplate.opsForValue().set(prefix, jsonToken, times, TimeUnit.SECONDS);
        //Redis里面存储一份  后期业务使用
        return R.build(TipUtil.LOGIN_SUCCESS, jsonToken);
    }

}
